package modules;

import java.util.Set;
import java.util.TreeMap;

import org.reflections.Reflections;
import org.reflections.scanners.SubTypesScanner;
import org.reflections.util.ClasspathHelper;
import org.reflections.util.ConfigurationBuilder;
import org.reflections.util.FilterBuilder;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;

/**
 * Starter class for all modules. Used as a gateway to all modules in
 * <code>genfamclust</code> package, and uses the corresponding class name
 * as a module identifier. There is only one entry point and modules are thus accessed by:
 * <code>java -jar GenFamClust-X.Y.Z.jar -Xmx3096m -Xms2048m [module-name] [module-specific-options] [args] </code>
 * 
 * @author Joel Sjöstrand.
 * @author Raja Hashim Ali.
 */
public class HomoComparaStarter {
	/**
	 * Starts a GenFamClust application located in the <code>modules</code> folder
	 * (or sub-folder).
	 * @param args program name, followed by arguments (and necessarily in that order).
	 * @throws Exception.
	 */
	public static void main(String[] args) throws Exception {
		
		// Find all starter methods in modules package.
		Logger logger = (Logger) Reflections.log;
		Level oldLvl = logger.getLevel();
		logger.setLevel(Level.OFF);
		Reflections reflections = new Reflections(
			    new ConfigurationBuilder()
			        .filterInputsBy(new FilterBuilder().include(FilterBuilder.prefix("modules")))
			        .setUrls(ClasspathHelper.forPackage("modules"))
			        .setScanners(new SubTypesScanner())
			        
			);
		Set<Class<? extends HomoCompara>> apps = reflections.getSubTypesOf(HomoCompara.class);
		logger.setLevel(oldLvl);
		
		// Create map linking name and module (we assume uniqueness).
		TreeMap<String, HomoCompara> map = new TreeMap<String, HomoCompara>();
		for (Class<? extends HomoCompara> c : apps) {
			try {
				// NOTE: Empty constructor assumed!!!!
				HomoCompara app = c.newInstance();
				map.put(app.getModuleName(), app);
			} catch (InstantiationException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}
		}
		
		if (args.length < 1 || args[0].equalsIgnoreCase("-h") || args[0].equalsIgnoreCase("--help")) {
			// No module specified.
			System.out.println(
					"================================================================================\n" +
					"HomoCompara is a Java library for primarily comparative homology designed and developed by\n" +
					"Raja Hashim Ali at Science for Life Laboratory (SciLifeLab) in Stockholm, Sweden.\n\n" +
					"Releases, source code and tutorial: http://code.google.com/p/homoclust/\n\n" +
					"License: HomoCompara is available under the New BSD License.\n"
					);
			System.out.println("Usage: homocompara-x.y.z.jar <module> [options] <arguments>\n");
			System.out.println("List of available modules:");
			for (String k : map.keySet()) {
				System.out.println("    " + k);
			}
			System.out.println("You can usually obtain module-specific help thus:\n" +
					"    java -jar homocompara-x.y.z.jar <module> -h");
			System.out.println("================================================================================\n");
		} else if (!map.containsKey(args[0])) {
			System.out.println("Unknown module. Use -h to show help.");
			System.out.println("Usage: java -jar homocompara-x.y.z.jar <module> [options] <arguments>");
		} else {
			// Start module. Remove module name first, though.
			String[] moduleArgs = new String[args.length - 1];
			System.arraycopy(args, 1, moduleArgs, 0, moduleArgs.length);
			HomoCompara module = map.get(args[0]);
			module.main(moduleArgs);
		}
	}
}
